//
// Created by hamlet on 2022/1/14.
//

#include "messageutil.h"
#include "player.h"
#include <QJsonArray>

UnknownMessage::UnknownMessage() : Message(Message::Type::Unknown) {
}

QJsonObject UnknownMessage::toJson() const {
    return {{"type", static_cast<int>(getType())}};
}

DeleteRoomMessage::DeleteRoomMessage(qint64 room_id) :
        Message(Message::Type::DeleteRoomMessage), p_roomID(room_id) {
}

DeleteRoomMessage *DeleteRoomMessage::parseJson(const QJsonObject &json) {
    return new DeleteRoomMessage{json["data"].toInteger()};
}

QJsonObject DeleteRoomMessage::toJson() const {
    return {{"type", static_cast<int>(getType())},
            {"data", p_roomID}};
}

AllPlayerInfo::AllPlayerInfo(const std::vector<PlayerInfo *> &playerList) :
        Message(Message::Type::AllPlayerInfo), p_playerList(playerList) {
}

AllPlayerInfo *AllPlayerInfo::parseJson(const QJsonObject &json) {
    auto array = json["data"].toArray();
    auto playerList = new std::vector<PlayerInfo *>;
    for (auto player_json: array) {
        playerList->push_back(PlayerInfo::parseJson(player_json.toObject()));
    }
    auto allPlayerInfo = new AllPlayerInfo(*playerList);
    allPlayerInfo->m_playerList = playerList;
    return allPlayerInfo;
}

QJsonObject AllPlayerInfo::toJson() const {
    QJsonArray array;
    for (const auto playerInfo: p_playerList)
        if (playerInfo)
            array << playerInfo->toJson();
    return {{"type", static_cast<int>(getType())},
            {"data", qMove(array)}};
}

NewPlayerMessage::NewPlayerMessage(const PlayerInfo *player) :
        Message(Message::Type::NewPlayerMessage), p_player(player) {
}

NewPlayerMessage *NewPlayerMessage::parseJson(const QJsonObject &json) {
    auto player = PlayerInfo::parseJson(json["data"].toObject());
    auto newPlayerMessage = new NewPlayerMessage(player);
    newPlayerMessage->m_player = player;
    return newPlayerMessage;
}

QJsonObject NewPlayerMessage::toJson() const {
    return {{"type", static_cast<int>(getType())},
            {"data", qMove(p_player->toJson())}};
}

DeletePlayerMessage::DeletePlayerMessage(qint64 player_id) :
        Message(Message::Type::DeletePlayerMessage), p_playerID(player_id) {
}

DeletePlayerMessage *DeletePlayerMessage::parseJson(const QJsonObject &json) {
    return new DeletePlayerMessage{json["data"].toInteger()};
}

QJsonObject DeletePlayerMessage::toJson() const {
    return {{"type", static_cast<int>(getType())},
            {"data", p_playerID}};
}

TextMessage::TextMessage(const QString &text) :
        Message(Message::Type::TextMessage), p_text(text) {
}

TextMessage *TextMessage::parseJson(const QJsonObject &json) {
    auto text = new QString{qMove(json["data"].toString())};
    auto textMessage = new TextMessage(*text);
    textMessage->m_text = text;
    return textMessage;
}

QJsonObject TextMessage::toJson() const {
    return {{"type", static_cast<int>(getType())},
            {"data", p_text}};
}

SnakeDirectionChangeMessage::SnakeDirectionChangeMessage(qint64 player_id, Snake::Direction direction, int time_stamp)
        : Message(Message::Type::SnakeDirectionChangeMessage),
          p_playerID(player_id), p_direction(direction), p_timeStamp(time_stamp) {
}

SnakeDirectionChangeMessage *SnakeDirectionChangeMessage::parseJson(const QJsonObject &json) {
    auto data = json["data"].toObject();
    return new SnakeDirectionChangeMessage{
            data["id"].toInteger(),
            static_cast<Snake::Direction>(data["dir"].toInt()),
            data["timeStamp"].toInt()
    };
}

QJsonObject SnakeDirectionChangeMessage::toJson() const {
    QJsonObject data{{"id",        p_playerID},
                     {"dir",       static_cast<int>(p_direction)},
                     {"timeStamp", p_timeStamp}};
    return {{"type", static_cast<int>(getType())},
            {"data", qMove(data)}};
}

StartGameMessage::StartGameMessage(int time_stamp) :
        Message(Message::Type::StartGameMessage), p_timeStamp(time_stamp) {
}

StartGameMessage *StartGameMessage::parseJson(const QJsonObject &json) {
    return new StartGameMessage{json["data"].toInt()};
}

QJsonObject StartGameMessage::toJson() const {
    return {{"type", static_cast<int>(getType())},
            {"data", p_timeStamp}};
}

NewFruitMessage::NewFruitMessage(QPoint fruit_pos, RoomInfo::FruitType fruit_type, int time_stamp) :
        Message(Message::Type::NewFruitMessage),
        p_fruitPos(qMove(fruit_pos)), p_fruitType(fruit_type), p_timeStamp(time_stamp) {
}

NewFruitMessage *NewFruitMessage::parseJson(const QJsonObject &json) {
    auto data = json["data"].toObject();
    return new NewFruitMessage{QPoint{data["pos_x"].toInt(), data["pos_y"].toInt()},
                               static_cast<RoomInfo::FruitType>(data["fruitType"].toInt()),
                               data["timeStamp"].toInt()};
}

QJsonObject NewFruitMessage::toJson() const {
    QJsonObject data{{"pos_x", p_fruitPos.x()}, {"pos_y", p_fruitPos.y()},
                     {"fruitType", static_cast<int>(p_fruitType)},
                     {"timeStamp", p_timeStamp}};
    return {{"type", static_cast<int>(getType())},
            {"data", qMove(data)}};
}

#pragma clang diagnostic push
#pragma ide diagnostic ignored "ConstantConditionsOC"

AllPlayerInfo::~AllPlayerInfo() {
    if (m_playerList) {
        for (auto player: *m_playerList)
            delete player;
        delete m_playerList;
    }
}

void AllPlayerInfo::GIVE_OWNERSHIP() {
    if (m_playerList) m_playerList->clear();
}

NewPlayerMessage::~NewPlayerMessage() {
    delete m_player;
}

PlayerInfo *NewPlayerMessage::GIVE_OWNERSHIP() {
    auto tmp = m_player;
    m_player = nullptr;
    return tmp;
}

TextMessage::~TextMessage() {
    delete m_text;
}

#pragma clang diagnostic pop
